import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.Locale;
import java.util.Random; 



import pluginUtils.Circle;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.MobiusTransform;
import pluginUtils.CircleInversion;
import pluginUtils.PackCircle;
import pluginUtils.Point2D;
import pluginUtils.Pos3D;
import pluginUtils.Sphere;
import pluginUtils.SphereInversion;

// La version actuelle est #360

public class GenericDrawerDF extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	
	private PrintStream output;
	private double xShift=0; 
	private double zShift=0; 
	
	

	private Random generator=new Random(); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	private String[] palette={"Yellow","Red","Blue","Green","White","NavyBlue","Turquoise","Orange"};
	private Color[] palette1={Color.YELLOW,Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA,Color.ORANGE};
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	private void drawCircle(Point2D C,double r){
		double xCenter=C.getX(); 
		double yCenter=C.getY(); 
		
		primeIP.setColor(Color.BLUE); 
		//drawPoint(xCenter,-yCenter);
		primeIP.setColor(Color.BLACK);
		
		int intX=(int)((xCenter)*acoef+ccoef);
		int intY=(int)((yCenter)*vcoef+wcoef);
		int intRx=(int)(r*acoef);
		int intRy=(int)(r*vcoef);
		
		
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
	}
	
	private void drawPoint(double x,double y){
		int radi=15; 
		int intX=(int)(x*acoef+ccoef);
		int intY=(int)(y*vcoef+wcoef);
		primeIP.fillOval(intX-radi,intY-radi,2*radi,2*radi);
	}
	
	private void drawPoint(Point2D p){
		int intX=(int)(p.getX()*acoef+ccoef);
		int intY=(int)(p.getY()*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	
	private void drawLine(Point2D p,Point2D q){
		int XD=(int)(p.getX()*acoef+ccoef); 
		int YD=(int)(p.getY()*vcoef+wcoef); 
		int XF=(int)(q.getX()*acoef+ccoef); 
		int YF=(int)(q.getY()*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	

	
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
	
		double limit=0.6; 
		double lmoins=-0.6;
		
		setBounds(lmoins,limit,lmoins,limit);
		setCoefs(); 
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		
		setProcessor("Verifying", primeIP);
		
		primeIP.setLineWidth(3);
		
		double a=0.7; 
		double b=1.8; 
		double R=0.07; 
		double rapports[]={b/a,1/a,1/b,a/b,a,b}; 
		Point2D lesZ[]=new Point2D[6]; 
		Point2D lesW[]=new Point2D[6];
		Point2D lesCentres[]=new Point2D[6];
		Point2D lesOps[]=new Point2D[6];
		drawCircle(new Point2D(0,0),R); 
		double thDeg[]=new double[6]; 
		
		double theta=0; 
		for(int i=0;i<6;i++){
			thDeg[i]=180*theta/Math.PI; 
			double u=R*(1+rapports[i]);
			double v=R*(1+rapports[(i+1)%6]); 
			double alpha=Math.acos((2*u*R+2*v*R-u*v-2*R*R)/(u*v)); 
			lesCentres[i]=new Point2D(u*Math.cos(theta),u*Math.sin(theta));
			lesZ[i]=new Point2D(R*Math.cos(theta),R*Math.sin(theta));
			lesOps[i]=new Point2D(R*(1+2*rapports[i])*Math.cos(theta),R*(1+2*rapports[i])*Math.sin(theta)); 
			drawPoint(lesZ[i]);
			drawPoint(lesOps[i]); 
			drawCircle(lesCentres[i],R*rapports[i]); 
			theta=theta+alpha; 
		}
		for(int i=0;i<6;i++)
			lesW[i]=Point2D.makePoint(lesCentres[i], lesCentres[(i+1)%6], rapports[(i+1)%6]/(rapports[i]+rapports[(i+1)%6])); 
		
		
		for(int i=0;i<6;i++){
		double angle=thDeg[(i+1)%6]-thDeg[i]; 
		if(angle<0) angle+=360; 
			System.out.println("traceArcDeCercleV2("+new Point2D(0,0).toPovray()+","+lesZ[i].toPovray()+","+lesZ[(i+1)%6].toPovray()+","+angle+",indmax,Blue)");
		
		}
		
		for(int i=0;i<6;i++){
			double A1=Point2D.distance(lesCentres[i], lesZ[i]); 
			double D1=Point2D.distance(lesZ[i],lesW[i]); 
			double angle=180/Math.PI*Math.acos(1-D1*D1/(2*A1*A1)); 	
			System.out.println("traceArcDeCercleV2("+lesCentres[i].toPovray()+","+lesW[i].toPovray()+","+lesZ[i].toPovray()+","+angle+",indmax,Red)");
		}
		for(int i=0;i<6;i++){
			double A1=Point2D.distance(lesCentres[i], lesZ[i]); 
			double D1=Point2D.distance(lesZ[i],lesW[(i+5)%6]); 
			double angle=180/Math.PI*Math.acos(1-D1*D1/(2*A1*A1)); 	
			System.out.println("traceArcDeCercleV2("+lesCentres[i].toPovray()+","+lesZ[i].toPovray()+","+lesW[(i+5)%6].toPovray()+","+angle+",indmax,Yellow)");
		}
		
		for(int i=0;i<6;i++){
			double A1=Point2D.distance(lesCentres[i], lesW[i]); 
			double D1=Point2D.distance(lesOps[i],lesW[i]); 
			double angle=180/Math.PI*Math.acos(1-D1*D1/(2*A1*A1)); 	
			System.out.println("traceArcDeCercleV2("+lesCentres[i].toPovray()+","+lesOps[i].toPovray()+","+lesW[i].toPovray()+","+angle+",indmax,Green)");
		}
		
		for(int i=0;i<6;i++){
			double A1=Point2D.distance(lesCentres[i], lesOps[i]); 
			double D1=Point2D.distance(lesOps[i],lesW[(i+5)%6]); 
			double angle=180/Math.PI*Math.acos(1-D1*D1/(2*A1*A1)); 	
			System.out.println("traceArcDeCercleV2("+lesCentres[i].toPovray()+","+lesOps[i].toPovray()+","+lesW[(i+5)%6].toPovray()+","+(-angle)+",indmax,Orange)");
		}
		
		/*
		// Point de contact des cercles exterieurs
		for(int i=0;i<6;i++){
			double angle=90-thDeg[i]; 
			double angle2=90-thDeg[(i+1)%6]; 
			//if(angle>angle2) angle2+=360; 
			System.out.println("traceArcDeCercle("+new Point2D(0,0).toPovray()+","+angle+","+angle2+","+R+",indmax,0,Red)"); 
			drawPoint(Point2D.makePoint(lesCentres[i], lesCentres[(i+1)%6], rapports[(i+1)%6]/(rapports[i]+rapports[(i+1)%6])));
			drawLine(lesCentres[i],lesCentres[(i+1)%6]);
		}
		for(int i=0;i<6;i++){
			double ay=lesZ[i].getY()-lesCentres[i].getY(); 
			double ax=lesZ[i].getX()-lesCentres[i].getX();
			double angle=90-180/Math.PI*Math.atan2(ay,ax); 
			
			ay=lesW[i].getY()-lesCentres[i].getY(); 
			ax=lesW[i].getX()-lesCentres[i].getX();
			double angle2=90-180/Math.PI*Math.atan2(ay,ax); 
			
			
			System.out.println("sphere{vtransform("+lesCentres[i].toPovray()+",transform{tournicotis}),0.005 texture{pigment{color Green}}}");
			System.out.println("sphere{vtransform("+lesZ[i].toPovray()+",transform{tournicotis}),0.005 texture{pigment{color Yellow}}}");
			System.out.println("sphere{vtransform("+lesW[i].toPovray()+",transform{tournicotis}),0.005 texture{pigment{color Yellow}}}"); 
			System.out.println("traceArcDeCercle("+lesCentres[i].toPovray()+","+angle+","+angle2+","+R*rapports[i]+",indmax,0,Blue)");
			
			ay=lesW[(i+1)%6].getY()-lesCentres[i].getY(); 
			ax=lesW[(i+1)%6].getX()-lesCentres[i].getX();
			angle2=90-180/Math.PI*Math.atan2(ay,ax); 
			System.out.println("traceArcDeCercle("+lesCentres[i].toPovray()+",ag+k*"+angle2+","+angle+","+R*rapports[i]+",indmax,0,Green)");
			
		}
		*/
			
		drawLine(new Point2D(0,0),lesCentres[0]); 
		

		
		
	
		show();
	}	
}
